using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using Microsoft.SqlServer.Management.Smo;


namespace DBSourceToolsLib
{
    public class DatabaseScriptOptions
    {
        private bool m_CreateScripts = false;
        private struct sTableScriptOptions
        {
            public bool bScriptData;
            public string strOrderByField;
        };

        public DatabaseScriptOptions(SourceDatabase m_ParentDatabase, bool bCreateScripts)
        {
            m_CreateScripts = bCreateScripts;
            m_SourceDatabase = m_ParentDatabase;
            this.m_OptionsFile = m_ParentDatabase.BaseDirectory + "\\ScriptOptions.xml";
            this.m_TableScriptOptionsXmlFile = m_ParentDatabase.BaseDirectory + "\\TableScriptOptions.xml";
            this.m_ViewScriptOptionsXmlFile = m_ParentDatabase.BaseDirectory + "\\ViewScriptOptions.xml";
            this.m_ProcScriptOptionsXmlFile = m_ParentDatabase.BaseDirectory + "\\StoredProcScriptOptions.xml";
            this.m_UserScriptOptionsXmlFile = m_ParentDatabase.BaseDirectory + "\\UserScriptOptions.xml";
            this.LoadScriptOptionsFromDisk(null);
            
        }

        private string m_OptionsFile;
        private SourceDatabase m_SourceDatabase = null;
        public bool ScriptDropAndCreate;
        public bool ScriptData;
        public bool ScriptTables;
        public bool ScriptStoredProcs;
        public bool ScriptViews;
        public bool ScriptUsers;
        public bool RefreshData;

        private string m_ScriptDatabasesXmlFile;
        private string m_BinDir;
        private string m_TableScriptOptionsXmlFile;
        private string m_ProcScriptOptionsXmlFile;
        private string m_ViewScriptOptionsXmlFile;
        private string m_UserScriptOptionsXmlFile;

        private Hashtable m_hashScriptOptions = new Hashtable();
        private Hashtable m_hashProcScriptOptions = new Hashtable();
        private Hashtable m_hashViewScriptOptions = new Hashtable();
        private Hashtable m_hashUserScriptOptions = new Hashtable();

        public event EventHandler<ProgressEventArgs> ProgressEventPublisher;

        public string ScriptDatabasesXmlFile
        {
            get { return m_ScriptDatabasesXmlFile; }
            set { m_ScriptDatabasesXmlFile = value; }
        }
        public string BinDir
        {
            get { return m_BinDir; }
            set { m_BinDir = value; }
        }
        public void LoadTableScriptOptionsFile(string strScriptOptionsXmlFile, EventHandler<ProgressEventArgs> localHandler)
        {
            this.m_hashScriptOptions.Clear();

            this.m_TableScriptOptionsXmlFile = strScriptOptionsXmlFile;
            if (System.IO.File.Exists(this.m_TableScriptOptionsXmlFile))
            {

                DBSourceToolsLib.DataSets.ScriptOptionsDS oScriptOptionsDs
                    = new DBSourceToolsLib.DataSets.ScriptOptionsDS();
                oScriptOptionsDs.ReadXml(this.m_TableScriptOptionsXmlFile);

                foreach (DBSourceToolsLib.DataSets.ScriptOptionsDS.ScriptOptionsRow _row in
                    oScriptOptionsDs.ScriptOptions)
                {
                    if (!m_hashScriptOptions.ContainsKey(_row.TableName))
                    {
                        if (_row.ScriptTable)
                        {
                            sTableScriptOptions sOptions = new sTableScriptOptions();
                            sOptions.bScriptData = _row.ScriptData;
                            sOptions.strOrderByField = _row.OrderByField;

                            m_hashScriptOptions.Add(_row.TableName, sOptions);
                        }
                    }
                }
            }
            else
            {
                //create the file.
                if ( m_CreateScripts && (m_SourceDatabase != null))
                {
                    DBSourceToolsLib.DataSets.ScriptOptionsDS tablesDs =
                        this.LoadTablesFromDB(this.m_SourceDatabase, localHandler, true);
                    FileUtils.EnsureFileIsWriteable(m_TableScriptOptionsXmlFile);
                    tablesDs.WriteXml(m_TableScriptOptionsXmlFile);

                }

            }

        }

        public bool MustScriptTable(string strTableName)
        {
            return m_hashScriptOptions.ContainsKey(strTableName);
        }

        public bool MustScriptData(string strTableName)
        {

            if (m_hashScriptOptions.ContainsKey(strTableName))
            {
                sTableScriptOptions oOptions = (sTableScriptOptions)m_hashScriptOptions[strTableName];
                return oOptions.bScriptData;
            }
            return false;
        }

        public DataSets.ScriptOptionsDS LoadTablesFromDB(
            DBSourceToolsLib.SourceDatabase oSourceDatabase,
            EventHandler<ProgressEventArgs> localHandler, bool bDefaultOption)
        {
//            EventHandler<ProgressEventArgs> localHandler = ProgressEventPublisher;
            DataSets.ScriptOptionsDS oDS = new DBSourceToolsLib.DataSets.ScriptOptionsDS();

            Microsoft.SqlServer.Management.Smo.Server oServer = oSourceDatabase.GetSmoServer();

            Microsoft.SqlServer.Management.Smo.Database oMDatabase = oSourceDatabase.GetSmoDatabase(oServer);

            oServer.SetDefaultInitFields(typeof(StoredProcedure), "IsSystemObject");

                //SysObjectsFactory oSysObjectsFactory = new SysObjectsFactory();
                int iTotalCount = oMDatabase.UserDefinedDataTypes.Count;
                int iProcessed = 0;

                iTotalCount = oMDatabase.Tables.Count;
                iProcessed = 0;

                foreach (Microsoft.SqlServer.Management.Smo.Table oSmo in oMDatabase.Tables)
                {
                    string strFullName = "";
                    if (oSmo.Schema.CompareTo("dbo") != 0)
                    {
                        strFullName = oSmo.Schema + "." + oSmo.Name;
                    }
                    else
                    {
                        strFullName = oSmo.Name;
                    }

                    if (localHandler != null)
                        localHandler(this, new ProgressEventArgs(iProcessed++, iTotalCount,
                            "Processing Table " + strFullName));

                    if (!oSmo.IsSystemObject)
                    {
                        oDS.ScriptOptions.AddScriptOptionsRow(strFullName, false, bDefaultOption, null);
                        //SOTable newSODataType = new SOTable(strFullName, this.m_SourceBaseDirectory, this.m_Database);
                        //this.m_SysObjectsList.Add(newSODataType.QualifiedName, newSODataType);
                    }
                }


            return oDS;

        }

        internal DBSourceToolsLib.DataSets.ScriptOptionsDS
            LoadStoredProcsFromDB(DBSourceToolsLib.SourceDatabase oSourceDatabase,
            EventHandler<ProgressEventArgs> localHandler, bool bDefaultFlag)
        {
//            EventHandler<ProgressEventArgs> localHandler = ProgressEventPublisher;
            DataSets.ScriptOptionsDS oDS = new DBSourceToolsLib.DataSets.ScriptOptionsDS();
            Microsoft.SqlServer.Management.Smo.Server oServer = oSourceDatabase.GetSmoServer();
            Microsoft.SqlServer.Management.Smo.Database oMDatabase = oSourceDatabase.GetSmoDatabase(oServer);

            oServer.SetDefaultInitFields(typeof(StoredProcedure), "IsSystemObject");

                //SysObjectsFactory oSysObjectsFactory = new SysObjectsFactory();
                int iTotalCount = oMDatabase.StoredProcedures.Count;
                int iProcessed = 0;

                foreach (Microsoft.SqlServer.Management.Smo.StoredProcedure oSmo in oMDatabase.StoredProcedures)
                {
                    string strFullName = "";
                    if (oSmo.Schema.CompareTo("dbo") != 0)
                    {
                        strFullName = oSmo.Schema + "." + oSmo.Name;
                    }
                    else
                    {
                        strFullName = oSmo.Name;
                    }

                    if (localHandler != null)
                        localHandler(this, new ProgressEventArgs(iProcessed++, iTotalCount,
                            "Processing Stored Procedure " + strFullName));

                    if (!oSmo.IsSystemObject)
                    {
                        oDS.ScriptOptions.AddScriptOptionsRow(strFullName, bDefaultFlag, bDefaultFlag, null);
                        //SOTable newSODataType = new SOTable(strFullName, this.m_SourceBaseDirectory, this.m_Database);
                        //this.m_SysObjectsList.Add(newSODataType.QualifiedName, newSODataType);
                    }
                }


            return oDS;
        }

        public void LoadProcsOptionsFile(string strScriptOptionsXmlFile, EventHandler<ProgressEventArgs> localHandler)
        {
            this.m_ProcScriptOptionsXmlFile = strScriptOptionsXmlFile;
            m_hashProcScriptOptions.Clear();

            if (System.IO.File.Exists(m_ProcScriptOptionsXmlFile))
            {
                DBSourceToolsLib.DataSets.ScriptOptionsDS oScriptOptionsDs
                    = new DBSourceToolsLib.DataSets.ScriptOptionsDS();
                oScriptOptionsDs.ReadXml(this.m_ProcScriptOptionsXmlFile);

                foreach (DBSourceToolsLib.DataSets.ScriptOptionsDS.ScriptOptionsRow _row in
                    oScriptOptionsDs.ScriptOptions)
                {
                    if (!m_hashProcScriptOptions.ContainsKey(_row.TableName))
                    {
                        if (_row.ScriptTable)
                        {
                            m_hashProcScriptOptions.Add(_row.TableName, _row.ScriptData);
                        }
                    }
                }
            }
            else
            {
                //create the file.
                if ( m_CreateScripts && (m_SourceDatabase != null))
                {
                    DBSourceToolsLib.DataSets.ScriptOptionsDS procDs =
                        this.LoadStoredProcsFromDB(this.m_SourceDatabase, localHandler, true);
                    FileUtils.EnsureFileIsWriteable(m_ProcScriptOptionsXmlFile);
                    procDs.WriteXml(m_ProcScriptOptionsXmlFile);
                    
                }

            }
        }

        public bool MustScriptProc(string strProcName)
        {
            return m_hashProcScriptOptions.ContainsKey(strProcName);
        }

        internal DBSourceToolsLib.DataSets.ScriptOptionsDS
            LoadViewsFromDB(DBSourceToolsLib.SourceDatabase oSourceDatabase,
            EventHandler<ProgressEventArgs> localHandler, bool bDefaultValue)
        {
//            EventHandler<ProgressEventArgs> localHandler = ProgressEventPublisher;
            DataSets.ScriptOptionsDS oDS = new DBSourceToolsLib.DataSets.ScriptOptionsDS();
            Microsoft.SqlServer.Management.Smo.Server oServer = oSourceDatabase.GetSmoServer();
            Microsoft.SqlServer.Management.Smo.Database oMDatabase = oSourceDatabase.GetSmoDatabase(oServer);

            oServer.SetDefaultInitFields(typeof(StoredProcedure), "IsSystemObject");

                //SysObjectsFactory oSysObjectsFactory = new SysObjectsFactory();
                int iTotalCount = oMDatabase.Views.Count;
                int iProcessed = 0;

                iTotalCount = oMDatabase.Views.Count;
                iProcessed = 0;

                foreach (Microsoft.SqlServer.Management.Smo.View oSmo in oMDatabase.Views)
                {
                    string strFullName = "";
                    if (oSmo.Schema.CompareTo("dbo") != 0)
                    {
                        strFullName = oSmo.Schema + "." + oSmo.Name;
                    }
                    else
                    {
                        strFullName = oSmo.Name;
                    }

                    if (localHandler != null)
                        localHandler(this, new ProgressEventArgs(iProcessed++, iTotalCount,
                            "Processing View " + strFullName));

                    if (!oSmo.IsSystemObject)
                    {
                        oDS.ScriptOptions.AddScriptOptionsRow(strFullName, bDefaultValue, bDefaultValue, null);
                        //SOTable newSODataType = new SOTable(strFullName, this.m_SourceBaseDirectory, this.m_Database);
                        //this.m_SysObjectsList.Add(newSODataType.QualifiedName, newSODataType);
                    }
                }


            return oDS;
        }


        public void LoadViewOptionsFile(string strViewOptionsXmlFile, EventHandler<ProgressEventArgs> localHandler)
        {
            m_hashViewScriptOptions.Clear();
            this.m_ViewScriptOptionsXmlFile = strViewOptionsXmlFile;

            if (System.IO.File.Exists(this.m_ViewScriptOptionsXmlFile))
            {
                DBSourceToolsLib.DataSets.ScriptOptionsDS oScriptOptionsDs
                    = new DBSourceToolsLib.DataSets.ScriptOptionsDS();
                oScriptOptionsDs.ReadXml(this.m_ViewScriptOptionsXmlFile);

                foreach (DBSourceToolsLib.DataSets.ScriptOptionsDS.ScriptOptionsRow _row in
                    oScriptOptionsDs.ScriptOptions)
                {
                    if (!m_hashViewScriptOptions.ContainsKey(_row.TableName))
                    {
                        if (_row.ScriptTable)
                        {
                            m_hashViewScriptOptions.Add(_row.TableName, _row.ScriptTable);
                        }
                    }
                }
            }
            else
            {
                //create the file.
                if ( m_CreateScripts &&  (m_SourceDatabase != null))
                {
                    DBSourceToolsLib.DataSets.ScriptOptionsDS viewsDs =
                        this.LoadViewsFromDB(this.m_SourceDatabase, localHandler, true);
                    FileUtils.EnsureFileIsWriteable(m_ViewScriptOptionsXmlFile);
                    viewsDs.WriteXml(m_ViewScriptOptionsXmlFile);

                }

            }

        }

        public bool MustScriptView(string strViewName)
        {
            if (m_hashViewScriptOptions.ContainsKey(strViewName))
                return (bool)m_hashViewScriptOptions[strViewName];
            return false;
        }

        internal string OrderByField(string strTableName)
        {
            if (m_hashScriptOptions.ContainsKey(strTableName))
            {
                sTableScriptOptions oOptions = (sTableScriptOptions)m_hashScriptOptions[strTableName];
                return oOptions.strOrderByField;
            }
            return null;
        }

        public void LoadScriptOptionsFromDisk(EventHandler<ProgressEventArgs> localHandler)
        {
            if (System.IO.File.Exists(m_OptionsFile))
            {
                System.Data.DataSet oDS = getDataSet();
                oDS.ReadXml(m_OptionsFile);
                this.ScriptData = Boolean.Parse(oDS.Tables[0].Rows[0]["MustScriptData"].ToString());
                this.ScriptStoredProcs = Boolean.Parse(oDS.Tables[0].Rows[0]["MustScriptProcs"].ToString());
                this.ScriptTables = Boolean.Parse(oDS.Tables[0].Rows[0]["MustScriptTables"].ToString());
                this.ScriptViews = Boolean.Parse(oDS.Tables[0].Rows[0]["MustScriptViews"].ToString());
                this.ScriptDropAndCreate = Boolean.Parse(oDS.Tables[0].Rows[0]["DropAndCreate"].ToString());
                this.ScriptUsers = Boolean.Parse(oDS.Tables[0].Rows[0]["MustScriptUsers"].ToString());
            }
            else
            {
                this.ScriptData = false;
                this.ScriptStoredProcs = true;
                this.ScriptTables = true;
                this.ScriptViews = true;
                this.ScriptDropAndCreate = true;
                this.ScriptUsers = true;
                WriteToDisk();
            }
            LoadProcsOptionsFile(this.m_ProcScriptOptionsXmlFile, localHandler);
            LoadTableScriptOptionsFile(this.m_TableScriptOptionsXmlFile, localHandler);
            LoadViewOptionsFile(this.m_ViewScriptOptionsXmlFile, localHandler);
            LoadUsersOptionsFile(this.m_UserScriptOptionsXmlFile, localHandler);
        }


        public void WriteToDisk()
        {
            string strScriptFileDir = this.m_OptionsFile.Substring(0, this.m_OptionsFile.LastIndexOf("\\"));
            if (!System.IO.Directory.Exists(strScriptFileDir))
                System.IO.Directory.CreateDirectory(strScriptFileDir);
            System.Data.DataSet oDS = getDataSet();
            oDS.Tables[0].Rows.Add("");
            oDS.Tables[0].Rows[0]["MustScriptData"] = this.ScriptData;
            oDS.Tables[0].Rows[0]["MustScriptProcs"] = this.ScriptStoredProcs;
            oDS.Tables[0].Rows[0]["MustScriptTables"] = this.ScriptTables;
            oDS.Tables[0].Rows[0]["MustScriptViews"] = this.ScriptViews;
            oDS.Tables[0].Rows[0]["MustScriptUsers"] = this.ScriptUsers;
            oDS.Tables[0].Rows[0]["DropAndCreate"] = this.ScriptDropAndCreate;

            FileUtils.EnsureFileIsWriteable(this.m_OptionsFile);
            oDS.WriteXml(this.m_OptionsFile);
        }

        private System.Data.DataSet getDataSet()
        {
            System.Data.DataSet oDs = new System.Data.DataSet();
            System.Data.DataTable oTable = oDs.Tables.Add("ScriptOptions");
            oTable.Columns.Add("MustScriptData");
            oTable.Columns.Add("MustScriptProcs");
            oTable.Columns.Add("MustScriptTables");
            oTable.Columns.Add("MustScriptViews");
            oTable.Columns.Add("MustScriptUsers");
            oTable.Columns.Add("DropAndCreate");
            return oDs;
        }

        internal DBSourceToolsLib.DataSets.ScriptOptionsDS
            LoadUsersFromDB(DBSourceToolsLib.SourceDatabase oSourceDatabase, 
            EventHandler<ProgressEventArgs> localHandler, bool bDefaultValue)
        {

            DBSourceToolsLib.DataSets.ScriptOptionsDS oDS = new DBSourceToolsLib.DataSets.ScriptOptionsDS();
            Microsoft.SqlServer.Management.Smo.Server oServer = oSourceDatabase.GetSmoServer();

            Microsoft.SqlServer.Management.Smo.Database oMDatabase = oSourceDatabase.GetSmoDatabase(oServer);

            int iTotalCount = oMDatabase.Users.Count;
            int iProcessed = 0;

            foreach (Microsoft.SqlServer.Management.Smo.User oUser in oMDatabase.Users)
            {
                if (localHandler != null)
                    localHandler(this, new ProgressEventArgs(iProcessed++, iTotalCount,
                        "Processing User " + oUser.Name));

                if (!oUser.IsSystemObject)
                    oDS.ScriptOptions.AddScriptOptionsRow(oUser.Name, bDefaultValue, bDefaultValue, null);

            }
            return oDS;
        }

        private void LoadUsersOptionsFile(string strUserOptionsXmlFile, EventHandler<ProgressEventArgs> localHandler)
        {
            m_hashUserScriptOptions.Clear();
            this.m_UserScriptOptionsXmlFile = strUserOptionsXmlFile;

            if (System.IO.File.Exists(this.m_UserScriptOptionsXmlFile))
            {
                DBSourceToolsLib.DataSets.ScriptOptionsDS oScriptOptionsDs
                    = new DBSourceToolsLib.DataSets.ScriptOptionsDS();
                oScriptOptionsDs.ReadXml(this.m_UserScriptOptionsXmlFile);

                foreach (DBSourceToolsLib.DataSets.ScriptOptionsDS.ScriptOptionsRow _row in
                    oScriptOptionsDs.ScriptOptions)
                {
                    if (!m_hashUserScriptOptions.ContainsKey(_row.TableName))
                    {
                        if (_row.ScriptTable)
                        {
                            m_hashUserScriptOptions.Add(_row.TableName, _row.ScriptTable);
                        }
                    }
                }
            }
            else
            {
                //create the file.
                if ( m_CreateScripts &&  (m_SourceDatabase != null))
                {
                    DBSourceToolsLib.DataSets.ScriptOptionsDS usersDs =
                        this.LoadUsersFromDB(this.m_SourceDatabase, localHandler, true);
                    FileUtils.EnsureFileIsWriteable(m_UserScriptOptionsXmlFile);
                    usersDs.WriteXml(m_UserScriptOptionsXmlFile);

                }

            }

        }


        internal bool MustScriptUser(string strUserName)
        {
            if (m_hashUserScriptOptions.ContainsKey(strUserName))
                return (bool)m_hashUserScriptOptions[strUserName];
            return false;
        }
    }
}
